#pragma once
#include <boost/operators.hpp>
#include <ostream>
#include <sstream>
#include <string>

#include "detail/basic_formatter.hpp"
#include "inc_windows_h.hpp"
#include "guid_formatter.hpp"

namespace wxx
{
	struct guid : ::GUID, boost::equality_comparable<guid>
	{
		explicit guid()
		{
			::CoCreateGuid(this);
		}

		explicit guid(const ::GUID& other)
		{
			::CopyMemory(this, &other, sizeof(::GUID));
		}

		guid& operator= (const ::GUID& other)
		{
			::CopyMemory(this, &other, sizeof(::GUID));
			return *this;
		}

		bool operator== (const guid& other) const throw()
		{
			return ::IsEqualGUID(*this, other) == TRUE;
		}

		template <class _Elem, class _Traits, class _Alloc>
		operator std::basic_string<_Elem, _Traits, _Alloc>() const
		{
			std::basic_stringstream<_Elem, _Traits, _Alloc> stream;
			stream << *this;

			return stream.str();
		}

		static std::ios_base& noshowbraces(std::ios_base& ios)
		{
			modifiers.noshowbraces(ios, true);
			return ios;
		}

		static std::ios_base& showbraces(std::ios_base& ios)
		{
			modifiers.noshowbraces(ios, false);
			return ios;
		}

		static std::ios_base& noshowhyphens(std::ios_base& ios)
		{
			modifiers.noshowhyphens(ios, true);
			return ios;
		}

		static std::ios_base& showhyphens(std::ios_base& ios)
		{
			modifiers.noshowhyphens(ios, false);
			return ios;
		}

		static const ::GUID empty;

	private:

		struct ios_modifier : detail::ios_modifier
		{
			enum
			{
				bit_noshowbraces = 1, 
				bit_noshowhyphens = 2
			};

#define WXX_ios_modbit(name)                                \
			bool name(std::ios_base& ios) const             \
			{                                               \
				return get_bit(ios, bit_##name);            \
			}                                               \
			void name(std::ios_base& ios, bool value) const \
			{                                               \
				set_bit(ios, bit_##name, value);            \
			}

			WXX_ios_modbit(noshowbraces);
			WXX_ios_modbit(noshowhyphens);
#undef WXX_ios_modbit
		};
		
		static const ios_modifier modifiers;

		template <class Ch, class Tr>
		friend struct detail::guid_formatter;
	};

	template<class Ch, class Tr>
	std::basic_ostream<Ch, Tr>& 
	operator<< (std::basic_ostream<Ch, Tr>& output, const ::GUID& g)
	{
		return detail::guid_formatter<Ch, Tr>(g).write_to(output);
	}

	template<class Ch, class Tr>
	std::basic_istream<Ch, Tr>&
	operator>> (std::basic_istream<Ch, Tr>& input, ::GUID& g)
	{
		return detail::guid_parser<Ch, Tr>(input).read(g);
	}
}